#include "modules/rtp_rtcp/rtcp_receiver.h"
#include <modules/rtp_rtcp/source/rtcp_packet/sender_report.h>
#include <modules/rtp_rtcp/source/rtcp_packet/receiver_report.h>
#include <modules/rtp_rtcp/source/rtcp_packet/extended_reports.h>
#include <modules/rtp_rtcp/source/rtcp_packet/nack.h>
#include <modules/rtp_rtcp/source/time_util.h>
#include <rtc_base/logging.h>
namespace xrtc
{

    struct RTCPReceiver::PacketInformation
    {
    };

    RTCPReceiver::RegisteredSsrcs::RegisteredSsrcs(const RtpRtcpConfig &config)
    {
        ssrcs_.push_back(config.local_media_ssrc);
        if (config.rtx_send_ssrc > 0)
        {
            ssrcs_.push_back(config.rtx_send_ssrc);
        }
    }
    bool RTCPReceiver::RegisteredSsrcs::Contains(uint32_t ssrc)
    {
        for (auto item : ssrcs_)
        {
            if (ssrc == item)
            {
                return true;
            }
        }
        return false;
    }
    RTCPReceiver::RTCPReceiver(const RtpRtcpConfig &config) : clock_(config.clock),
                                                              audio_(config.audio),
                                                              main_ssrc_(config.local_media_ssrc),
                                                              rtp_rtcp_module_observer_(config.rtp_rtcp_module_observer),
                                                              enable_xr_(config.enable_xr),
                                                              registered_ssrcs_(config)
    {
    }
    RTCPReceiver::~RTCPReceiver()
    {
    }
    void RTCPReceiver::SetRemoteSsrc(uint32_t ssrc)
    {
        remote_ssrc_ = ssrc;
    }
    bool RTCPReceiver::NTP(
        uint32_t *received_ntp_secs,
        uint32_t *received_ntp_fract,
        uint32_t *rtcp_arrival_time_secs,
        uint32_t *rtcp_arrival_time_fract,
        uint32_t *rtp_timestamp)
    {
        if (!last_received_sr_ntp_.Valid())
        { // 此时还没有收到任何的SR包
            return false;
        }
        // SR包中的NTP时间的秒数部分
        if (received_ntp_secs)
        {
            *received_ntp_secs = remote_sender_ntp_time_.seconds();
        }
        // SR包中的NTP时间的秒数以下的部分
        if (received_ntp_fract)
        {
            *received_ntp_fract = remote_sender_ntp_time_.fractions();
        }
        // SR 包到达时的本地NTP时间
        if (rtcp_arrival_time_secs)
        {
            *rtcp_arrival_time_secs = last_received_sr_ntp_.seconds();
        }
        if (rtcp_arrival_time_fract)
        {
            *rtcp_arrival_time_fract = last_received_sr_ntp_.fractions();
        }
        // SR 包的RTP timestamp
        if (rtp_timestamp)
        {
            *rtp_timestamp = remote_sender_rtp_time_;
        }
        return true;
    }
    void RTCPReceiver::IncomingRtcpPacket(const uint8_t *packet, size_t packet_length)
    {
        IncomingRtcpPacket(rtc::ArrayView<const uint8_t>(packet, packet_length));
    }
    void RTCPReceiver::IncomingRtcpPacket(rtc::ArrayView<const uint8_t> packet)
    {
        if (packet.empty())
        {
            RTC_LOG(LS_WARNING) << "incoming rtcp packet is empty";
            return;
        }
        PacketInformation packet_information;
        if (!ParseCompoundPacket(packet, &packet_information))
        {
            return;
        }
    }

    bool RTCPReceiver::ParseCompoundPacket(rtc::ArrayView<const uint8_t> packet,
                                           PacketInformation *packet_information)
    {
        webrtc::rtcp::CommonHeader rtcp_block;
        for (const uint8_t *next_block = packet.begin(); next_block != packet.end();
             next_block = rtcp_block.NextPacket())
        {
            ptrdiff_t remaining_block_size = packet.end() - next_block;
            if (!rtcp_block.Parse(next_block, remaining_block_size))
            {
                if (next_block == packet.begin())
                {
                    RTC_LOG(LS_WARNING) << "invalid incoming rtcp packet";
                    return false;
                }
                ++num_skipped_packets_;
                break;
            }

            switch (rtcp_block.type())
            {
            case webrtc::rtcp::SenderReport::kPacketType:
                HandleSr(rtcp_block, packet_information);
                break;
            case webrtc::rtcp::ReceiverReport::kPacketType:
                HandleRr(rtcp_block, packet_information);
                break;
            case webrtc::rtcp::Rtpfb::kPacketType:
                switch (rtcp_block.fmt())
                {
                case webrtc::rtcp::Nack::kFeedbackMessageType:
                    // nack
                    HandleNack(rtcp_block, packet_information);
                    break;
                default:
                    ++num_skipped_packets_;
                    break;
                }
                break;
            case webrtc::rtcp::ExtendedReports::kPacketType:
                HandleXr(rtcp_block, packet_information);
                break;
            default:
                RTC_LOG(LS_WARNING) << "unknown rtcp packet_type :" << rtcp_block.type();
                ++num_skipped_packets_;
                break;
            }
        }
        return true;
    }
    void RTCPReceiver::HandleSr(const webrtc::rtcp::CommonHeader &rtcp_block,
                                PacketInformation *packet_information)
    {
        webrtc::rtcp::SenderReport sr;
        if (!sr.Parse(rtcp_block))
        {
            ++num_skipped_packets_;
            return;
        }
        uint32_t remote_ssrc = sr.sender_ssrc();
        if (remote_ssrc == remote_ssrc_)
        {
            // RTC_LOG(LS_WARNING) << "===sr ssrc:" << sr.sender_ssrc()
            //                     << ",packet_count:" << sr.sender_packet_count();
            remote_sender_ntp_time_ = sr.ntp();
            remote_sender_rtp_time_ = sr.rtp_timestamp();
            last_received_sr_ntp_ = clock_->CurrentNtpTime();
            remote_sender_packet_count_ = sr.sender_packet_count();
            remote_sender_octet_count_ = sr.sender_octet_count();
            if (rtp_rtcp_module_observer_)
            {
                rtp_rtcp_module_observer_->OnSrInfo(audio_ ? webrtc::MediaType::AUDIO : webrtc::MediaType::VIDEO,
                                                    sr.rtp_timestamp(), sr.ntp());
            }
        }
    }
    void RTCPReceiver::HandleRr(const webrtc::rtcp::CommonHeader &rtcp_block, PacketInformation *packet_information)
    {
    }
    void RTCPReceiver::HandleNack(const webrtc::rtcp::CommonHeader &rtcp_block, PacketInformation *packet_information)
    {
        webrtc::rtcp::Nack nack;
        if (!nack.Parse(rtcp_block))
        {
            ++num_skipped_packets_;
            return;
        }
        if (main_ssrc_ != nack.media_ssrc())
        {
            return;
        }
        if (rtp_rtcp_module_observer_)
        {
            rtp_rtcp_module_observer_->OnNackReceived(audio_ ? webrtc::MediaType::AUDIO : webrtc::MediaType::VIDEO, nack.packet_ids());
        }
    }
    void RTCPReceiver::HandleXr(const webrtc::rtcp::CommonHeader &rtcp_block, PacketInformation *packet_information)
    {
        webrtc::rtcp::ExtendedReports xr;
        if (!xr.Parse(rtcp_block))
        {
            ++num_skipped_packets_;
            return;
        }
        for (const webrtc::rtcp::ReceiveTimeInfo time_info : xr.dlrr().sub_blocks())
        {
            HandleXrDlrrReportBlock(xr.sender_ssrc(), time_info);
        }
    }

    void RTCPReceiver::HandleXrDlrrReportBlock(uint32_t ssrc, const webrtc::rtcp::ReceiveTimeInfo &rti)
    {
        if (!registered_ssrcs_.Contains(rti.ssrc))
        {
            return;
        }
        if (!enable_xr_)
        {
            return;
        }
        uint32_t send_ntp_time = rti.last_rr;
        if (0 == send_ntp_time)
        {
            return;
        }
        uint32_t delay_ntp_time = rti.delay_since_last_rr;
        uint32_t now_ntp = webrtc::CompactNtp(clock_->CurrentNtpTime());
        uint32_t rtt_ntp = now_ntp - delay_ntp_time - send_ntp_time;
        xr_rr_rtt_ms_ = webrtc::CompactNtpRttToMs(rtt_ntp);

        if (rtp_rtcp_module_observer_)
        {
            rtp_rtcp_module_observer_->OnRttUpdate(xr_rr_rtt_ms_);
        }
    }

} // namespace xrtc
